package com.dly.hope.service.impl;

import com.dly.hope.constant.ExceptionConstant;
import com.dly.hope.dao.WebSocketMessageDao;
import com.dly.hope.model.vo.FriendAddMessageVo;
import com.dly.hope.model.vo.FriendGroupVo;
import com.dly.hope.model.vo.FriendShowVo;
import com.dly.hope.modle.Friend;
import com.dly.hope.modle.FriendGroup;
import com.dly.hope.modle.UserAccount;
import com.dly.hope.repository.FriendGroupRepository;
import com.dly.hope.repository.FriendRepository;
import com.dly.hope.repository.SessionRepository;
import com.dly.hope.repository.UserAccountRepository;
import com.dly.hope.service.TieService;
import com.dly.hope.type.MessageType;
import com.dly.hope.utils.ExceptionPropertiesUtil;
import com.dly.hope.webSocket.WebSocketServer;
import com.dly.hope.webSocket.dto.MessageDto;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TieServiceImpl implements TieService {

    @Resource
    private FriendGroupRepository friendGroupRepository;

    @Resource
    private FriendRepository friendRepository;

    @Resource
    private UserAccountRepository userAccountRepository;

    @Resource
    private SessionRepository sessionRepository;

    @Resource
    private WebSocketMessageDao webSocketMessageDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createFriendGroup(String name, String userId) {
        if (friendGroupRepository.findTopByNameAndCreateUserAndDataStatus(name, userId, 1).isPresent()) {
            throw ExceptionPropertiesUtil.getException(ExceptionConstant.FRIEND_GROUP_EXIT);
        }

        FriendGroup friendGroup = new FriendGroup();
        friendGroup.setName(name);
        friendGroupRepository.save(friendGroup);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFriendGroup(String friendGroupId, String name, String userId) {
        friendGroupRepository.findByIdAndDataStatus(friendGroupId, 1)
                .filter(friendGroup -> friendGroup.getCreateUser().equals(userId))
                .map(friendGroup -> {
                    friendGroup.setName(name);
                    return true;
                }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addFriend(String userNumber, String friendGroupId, String userId) {

        UserAccount userAccount = userAccountRepository.findByAccountNumberAndDataStatus(userNumber, 1)
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.USER_ACCOUNT_NULL));

        add(userAccount, friendGroupId, userId);
    }

    private void add(UserAccount userAccount,  String friendGroupId, String userId){

        if(userId.equals(userAccount.getId())){
            throw ExceptionPropertiesUtil.getException(ExceptionConstant.NOT_ADD_SELF);
        }

        //自动拒绝
        if(userAccount.getRefuseAgree() == 1){
            throw ExceptionPropertiesUtil.getException(ExceptionConstant.REFUSE);
        }

        if(userAccount.getAutoAgree() == 1 ){
            //自动添加好友
            friendGroupRepository.findTopByNameAndCreateUserAndDataStatus("默认分组", userAccount.getId(), 1)
                    .ifPresent(friendGroup -> {
                        Friend friend1 = new Friend();
                        friend1.setFriendId(userAccount.getId());
                        friend1.setUserId(userId);
                        friend1.setFriendGroupId(friendGroupId);
                        friend1.setIsAgree(1);

                        Friend friend2 = new Friend();
                        friend2.setFriendId(userId);
                        friend2.setUserId(userAccount.getId());
                        friend2.setFriendGroupId(friendGroup.getId());
                        friend2.setIsAgree(1);
                        friendRepository.save(friend1);
                        friendRepository.save(friend2);

                        UserAccount userAccount1 = userAccountRepository.findByIdAndDataStatus(userId, 1).orElseThrow();
                        MessageDto messageDto = new MessageDto();
                        messageDto.setType(MessageType.ADDFRIEND);
                        WebSocketServer.invite(messageDto, userAccount1, userAccount);
                    });
            return;
        }

        friendGroupRepository.findByIdAndDataStatus(friendGroupId, 1)
                .filter(friendGroup -> friendGroup.getCreateUser().equals(userId))
                .map(friendGroup -> {
                    //一个人只可以添加一个人一次
                    if (friendRepository.findTopByUserIdAndFriendIdAndDataStatus(userId, userAccount.getId(), 1).isPresent()) {
                        throw ExceptionPropertiesUtil.getException(ExceptionConstant.FRIEND_EXIT);
                    }

                    Friend friend = new Friend();
                    friend.setFriendId(userAccount.getId());
                    friend.setFriendGroupId(friendGroupId);
                    friend.setUserId(friendGroup.getCreateUser());
                    friendRepository.save(friend);

                    UserAccount userAccount1 = userAccountRepository.findByIdAndDataStatus(userId, 1).orElseThrow();
                    MessageDto messageDto = new MessageDto();
                    messageDto.setType(MessageType.ADDFRIEND);
                    WebSocketServer.invite(messageDto, userAccount1, userAccount);
                    return true;
                }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addFriendId(String friendId, String friendGroupId, String userId) {
        UserAccount userAccount = userAccountRepository.findByIdAndDataStatus(friendId, 1)
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.USER_ACCOUNT_NULL));
        add(userAccount, friendGroupId, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agreeFriend(String id, String userId, String friendGroupId) {
        friendRepository.findByIdAndFriendIdAndIsAgreeAndDataStatus(id, userId, 0, 1).map(friend -> {
            friend.setIsAgree(1);

            //两边都添加
            Friend friend1 = new Friend();
            friend1.setFriendGroupId(friendGroupId);
            friend1.setUserId(friend.getFriendId());
            friend1.setFriendId(friend.getUserId());
            friend1.setIsAgree(1);
            friendRepository.save(friend1);

            return true;
        }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refusalFriend(String id, String userId) {
        friendRepository.findByIdAndFriendIdAndIsAgreeAndDataStatus(id, userId, 0, 1)
                .map(friend -> {
                    friend.setDataStatus(0);
                    return true;
                })
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));
    }

    @Override
    public List<FriendAddMessageVo> getFriendAddMessage(String userId) {
        Map<String, Friend> friendMap = friendRepository.findAllByFriendIdAndIsAgreeAndDataStatus(userId, 0, 1)
                .stream()
                .collect(Collectors.toMap(Friend::getUserId, friend -> friend, (old, now) -> now));
        Map<String, UserAccount> userAccountMap = userAccountRepository.findAllByIdInAndDataStatus(new ArrayList<>(friendMap.keySet()), 1)
                .stream()
                .collect(Collectors.toMap(UserAccount::getId, userAccount -> userAccount, (old, now) -> now));

        List<FriendAddMessageVo> friendAddMessageVos = new ArrayList<>();
        friendMap.forEach((user, friend) -> {
            FriendAddMessageVo friendAddMessageVo = new FriendAddMessageVo();
            UserAccount userAccount = userAccountMap.get(user);
            friendAddMessageVo.setAvatar(userAccount.getAvatar());
            friendAddMessageVo.setName(userAccount.getAccountName());
            friendAddMessageVo.setId(friend.getId());
            friendAddMessageVos.add(friendAddMessageVo);
        });
        return friendAddMessageVos;
    }

    @Override
    public List<FriendGroupVo> getFriendGroupVo(String userId) {
        return friendGroupRepository.findAllByCreateUserAndDataStatus(userId, 1)
                .stream()
                .sorted((a1, a2)->{
                    //前一个的时间
                    Date date1 = a1.getCreateDate();
                    Date date2 = a2.getCreateDate();
                    if(date2.before(date1)){
                        return -1;
                    }
                    return 1;
                })
                .map(friendGroup -> {
                    FriendGroupVo friendGroupVo = new FriendGroupVo();
                    friendGroupVo.setFriendGroupId(friendGroup.getId());
                    friendGroupVo.setName(friendGroup.getName());
                    return friendGroupVo;
                })
                .collect(Collectors.toList());

    }

    @Override
    public List<FriendShowVo> getFriendShowVo(String userId) {
        List<FriendGroup> groups = friendGroupRepository.findAllByCreateUserAndDataStatus(userId, 1);
        List<String> groupIds = groups.stream().sorted((a1, a2)->{
            //前一个的时间
            Date date1 = a1.getCreateDate();
            Date date2 = a2.getCreateDate();
            if(date2.before(date1)){
                return -1;
            }
            return 1;
        }).map(FriendGroup::getId).collect(Collectors.toList());

        List<Friend> friends = friendRepository.findAllByFriendGroupIdInAndIsAgreeAndDataStatus(groupIds, 1, 1);
        List<String> friendIds = friends.stream().map(Friend::getFriendId).collect(Collectors.toList());
        Map<String, List<Friend>> groupMap = friends.stream().collect(Collectors.groupingBy(Friend::getFriendGroupId));

        Map<String, UserAccount> userAccountMap = userAccountRepository.findAllByIdInAndDataStatus(friendIds, 1)
                .stream()
                .collect(Collectors.toMap(UserAccount::getId, userAccount -> userAccount, (old, now) -> now));

        return groups.stream().map(friendGroup -> {
            FriendShowVo friendShowVo = new FriendShowVo();
            friendShowVo.setValue(friendGroup.getId());
            friendShowVo.setLabel(friendGroup.getName());
            List<FriendShowVo> children;
            //分组下面可以没有用户 会为空
            if (Objects.isNull(groupMap.get(friendGroup.getId()))) {
                children = new ArrayList<>();
            } else {
                children = groupMap.get(friendGroup.getId()).stream()
                        .map(friend -> {
                            FriendShowVo friendShowVo1 = new FriendShowVo();
                            friendShowVo1.setValue(friend.getFriendId());
                            UserAccount userAccount = userAccountMap.get(friend.getFriendId());
                            friendShowVo1.setLabel(userAccount.getAccountName());
                            return friendShowVo1;
                        }).collect(Collectors.toList());
            }
            friendShowVo.setChildren(children);
            return friendShowVo;
        }).collect(Collectors.toList());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeFriend(String userId, String friendId) {
        //删除好友关系
        remove(userId, friendId);
        remove(friendId, userId);
        //删除信息
        webSocketMessageDao.getMessage(userId,friendId).forEach(webSocketMessage -> {
            webSocketMessage.setDataStatus(0);
        });
    }

    private void remove(String userId, String friendId){
        friendRepository.findTopByUserIdAndFriendIdAndDataStatus(userId, friendId, 1).map(friend -> {
            friend.setDataStatus(0);
            //删除会话信息
            sessionRepository.findTopByUserIdAndSessionIdAndDataStatus(userId, friendId,1).ifPresent(session -> {
                session.setDataStatus(0);
            });
            return true;
        }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.FRIEND_NULL));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeFriendGroup(String userId, String friendGroupId) {
        //默认分组
        FriendGroup defaultFriendGroup = friendGroupRepository.findTopByNameAndCreateUserAndDataStatus("默认分组", userId, 1)
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.DEFAULT_GROUP_NULL));
        friendGroupRepository
                .findByIdAndDataStatus(friendGroupId,1)
                .filter(friendGroup -> friendGroup.getCreateUser().equals(userId))
                .filter(friendGroup -> !friendGroup.getName().equals("默认分组"))
                .map(friendGroup -> {
                    friendRepository.findAllByFriendGroupIdAndDataStatus(friendGroupId,1).forEach(friend -> {
                        if(friend.getIsAgree() == 0){
                            friend.setDataStatus(0);
                        }else{
                            //添加到默认分组
                            friend.setFriendGroupId(defaultFriendGroup.getId());
                        }
                    });
                    friendGroup.setDataStatus(0);
                    return true;
                })
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveFriendGroup(String userId, String friendId, String friendGroupId) {
        friendGroupRepository
                .findByIdAndDataStatus(friendGroupId,1)
                .filter(friendGroup -> friendGroup.getCreateUser().equals(userId))
                .map(friendGroup -> {
                    friendRepository.findTopByUserIdAndFriendIdAndDataStatus(userId, friendId,1).ifPresent(friend -> {
                        friend.setFriendGroupId(friendGroup.getId());
                    });
                    return true;
                })
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.NO_PERMISSION));
    }
}
